package cn.good.yan.service.impl;

import cn.good.yan.entity.Storage;
import cn.good.yan.entity.StorageTbl;
import cn.good.yan.mapper.StorageMapper;
import cn.good.yan.mapper.StorageTblMapper;
import cn.good.yan.service.StorageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


/**
 * 库存服务
 *
 * @author shengren.yan
 * @create 2024-02-22
 */
@Slf4j
@Service
public class StorageServiceImpl extends ServiceImpl<StorageMapper, Storage> implements StorageService {

    @Autowired
    StorageMapper storageMapper;

    // 扣除 该产品 的仓库的库存
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void decrease(Long productId, Integer count) {
        log.info("-----> storage减库存开始");
        // 这里的 写死的id，动态需要写活
        Storage storage = storageMapper.selectById(productId);
        storage.setUsed(storage.getUsed() + count);
        storage.setResidue(storage.getResidue() - count);
        storageMapper.updateById(storage);
        log.info("-----> storage减库存结束");
    }

    @Autowired
    StorageTblMapper tblMapper;

    // 扣除 该产品 的仓库的库存 - tcc模式
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeStockTcc(Long productId, Integer count) {
        // 全事务id
        String xid = RootContext.getXID();
        System.out.println("全事务id : " + xid);
        StorageTbl tbl = tblMapper.findByXid(xid);
        // a 如果已经有快照记录 - 代表已经回滚过数据
        if (tbl != null) {
            return;
        }

        // b 进行减库存  ，注意：这里的 productId 写死的是1，如果正则查询，需要写sql
        Storage storage = storageMapper.selectById(productId);
        storage.setUsed(storage.getUsed() + count);
        storage.setResidue(storage.getResidue() - count);
        storageMapper.updateById(storage);

        // c 记录快照数据
        StorageTbl storageTbl = new StorageTbl();
        storageTbl.setXid(xid);
        storageTbl.setProductId(storage.getProductId());
        storageTbl.setStatus(0);           // 进入 try 模式  ，值是0
        storageTbl.setFreezeTotal(count);  // 冻结的库存数量
        tblMapper.add(storageTbl);

    }

    // 不需要回滚执行方法逻辑
    @Override
    public boolean commitTcc(BusinessActionContext context) {
        // 全事务id
        String xid = context.getXid();
        // 删除快照信息  - 删除逻辑 不需要考虑 幂等性，因为删除多次删除无影响
        int row = tblMapper.deletePByXid(xid);
        return row == 1;
    }

    // 需要回滚执行方法逻辑
    @Override
    public boolean cancel(BusinessActionContext context) {
        // 全事务id
        String xid = context.getXid();
        StorageTbl tbl = tblMapper.findByXid(xid);
        // a 判断是否是空回滚
        // Long productId = (Long) context.getActionContext("num");
        Long productId = context.getActionContext("productId", Long.class);
        Integer count = context.getActionContext("count", Integer.class);
        System.out.println("通过上下文获取值：" + productId + " : " + count);
        if (null == tbl) {
            // b 这里逻辑：证明 try 方法还没执行，就执行了cancel方法，因为如果失败，会反复执行该需要回滚的方法
            StorageTbl accountTbl = new StorageTbl();
            accountTbl.setXid(xid);
            accountTbl.setProductId(productId);
            accountTbl.setStatus(2);      // 进入 rollback 模式  ，值是2
            accountTbl.setFreezeTotal(0); // 冻结库存- 进行清空
            tblMapper.add(accountTbl);
            return true;
        }
        // c 幂等性 - 它的状态已经是rollback 状态，就不需要执行下面的逻辑
        if (tbl.getStatus() == 2) {
            return true;
        }

        // d 回滚：恢复数据
        Storage storage = storageMapper.findByMid(tbl.getProductId());
        // Storage(id=1, productId=1, total=100, used=15, residue=85)
        System.out.println(storage);
        System.out.println(storage.getUsed());
        System.out.println(tbl.getFreezeTotal());
        System.out.println(storage.getUsed() + tbl.getFreezeTotal());
        storage.setUsed(storage.getUsed() - tbl.getFreezeTotal());
        storage.setResidue(storage.getResidue() + tbl.getFreezeTotal());
        storageMapper.updateById(storage);

        // e 将冻结的快照数据 - 清零
        tbl.setStatus(2);      // 进入 rollback 模式  ，值是2
        tbl.setFreezeTotal(0); // 冻结库存- 进行清空
        int row = tblMapper.updateByXid(tbl);
        return row == 1;

    }


}
